package org.wheel.plugins.toolkit.sql.segment;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.wheel.plugins.toolkit.jsqlparse.helper.ParamValueConvert;
import org.wheel.plugins.toolkit.sql.capability.LambdaColumnCompare;
import org.wheel.plugins.toolkit.sql.capability.LambdaCompare;
import org.wheel.plugins.toolkit.sql.capability.SqlCompare;
import org.wheel.plugins.toolkit.sql.core.AbstractWrapper;
import org.wheel.plugins.toolkit.sql.core.SqlSegment;
import org.wheel.plugins.toolkit.sql.core.Wrapper;
import org.wheel.plugins.toolkit.sql.enums.CompareType;
import org.wheel.plugins.toolkit.sql.helper.ColumnRef;
import org.wheel.plugins.toolkit.sql.helper.SFunction;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * ON 条件链式构造器 – 支持 Lambda/字符串双写法
 */
public final class OnClause<J> implements OnSegment
        , LambdaCompare<OnClause<J>, J>
        , LambdaColumnCompare<OnClause<J>, J>
        , SqlCompare<OnClause<J>, J> {

    private final String joinAlias;        // 当前 join 表别名（t2/t3…）
    private final AbstractWrapper<?, ?> wrapper;      // 主查询 wrapper（用于主表别名）
    private final List<String> conditions = CollUtil.newArrayList();

    public OnClause(String joinAlias, AbstractWrapper<?, ?> wrapper) {
        this.joinAlias = joinAlias;
        this.wrapper = wrapper;
    }

    /* ===== 实现 LambdaCompare & SqlCompare 的底层方法 ===== */

    @Override
    public <R> OnClause<J> compare(boolean condition, CompareType type, SFunction<R, ?> col, Object val) {
        if (!condition) return this;
        String column = ColumnRef.of(joinAlias, col, null).withoutAlias().withWrapper(wrapper).getSql();
        String param = ParamValueConvert.convertValuesToSqlString(val);
        conditions.add(StrUtil.format("{} {} {}", column, type.getOp(), param));
        return this;
    }

    @Override
    public <R> OnClause<J> compareList(boolean condition, CompareType type, SFunction<R, ?> col, Collection<?> val) {
        if (!condition || CollUtil.isEmpty(val)) return this;
        String column = ColumnRef.of(joinAlias, col, null).withoutAlias().withWrapper(wrapper).getSql();
        String inPart = val.stream()
                .map(ParamValueConvert::convertValuesToSqlString)
                .collect(Collectors.joining(", "));
        conditions.add(StrUtil.format("{} {} ({})", column, type.getOp(), inPart));
        return this;
    }

    @Override
    public OnClause<J> compare(boolean condition, CompareType type, String col, Object val) {
        if (!condition) return this;
        String column = col;
        String param = ParamValueConvert.convertValuesToSqlString(val);
        conditions.add(StrUtil.format("{} {} {}", column, type.getOp(), param));
        return this;
    }

    @Override
    public <R> OnClause<J> compareList(boolean condition, CompareType type, String col, Collection<?> val) {
        if (!condition || CollUtil.isEmpty(val)) return this;
        String column = col;
        String inPart = val.stream()
                .map(ParamValueConvert::convertValuesToSqlString)
                .collect(Collectors.joining(", "));
        conditions.add(StrUtil.format("{} {} ({})", column, type.getOp(), inPart));
        return this;
    }

    @Override
    public <D> OnClause<J> compareCol(CompareType type, String leftTableAlias, SFunction<J, ?> leftCol, String rightTableAlias, SFunction<D, ?> rightCol) {
        String left = ColumnRef.of(StrUtil.blankToDefault(leftTableAlias, this.joinAlias), leftCol, null).withoutAlias().withWrapper(wrapper).getSql();
        String right = ColumnRef.of(rightTableAlias, rightCol, null).withoutAlias().withWrapper(wrapper).getSql();
        conditions.add(StrUtil.format("{} {} {}", left, type.getOp(), right));
        return this;
    }
    /* ========== 字符串字段 – 兜底写法 ========== */
    public OnClause<J> eq(String leftCol, String rightCol) {
        conditions.add(StrUtil.format("{} = {}", leftCol, rightCol));
        return this;
    }
    public OnClause<J> eq(String leftCol, Object constant) {
        conditions.add(StrUtil.format("{} = {}", leftCol, constant));
        return this;
    }
    public OnClause<J> in(String leftCol, List<?> constants) {
        List<String> paramList = CollUtil.newArrayList();
        for (int i = 0; i < constants.size(); i++) {
            paramList.add(":param" + i);
        }
        String inPart = CollUtil.join(paramList, ", ");
        conditions.add(StrUtil.format("{} IN ({})", leftCol, inPart));
        return this;
    }

    /* ========== 渲染 ========== */
    @Override
    public String getSql() {
        return StrUtil.join(" AND ", conditions);
    }
}